package ximg

import (
	"errors"
	"image"
	"image/gif"
	"image/jpeg"
	"image/png"
	"io"
	"mime/multipart"

	"gitee.com/xuesongtao/gotool/internal"
	"golang.org/x/image/bmp"
	"golang.org/x/image/webp"
)

var (
	nullFn = func(img image.Image) image.Image { return img }
)

// ToImgFn 图片处理
type ToImgFn func(image.Image) image.Image

// Png
func Png(dest io.Writer, src multipart.File, fn ...ToImgFn) error {
	toFn := nullFn
	if len(fn) > 0 {
		toFn = fn[0]
	}

	img, err := png.Decode(src)
	if err != nil {
		return errors.New("png.Decode is failed, err: " + err.Error())
	}
	if err := png.Encode(dest, toFn(img)); err != nil {
		return errors.New("png.Encode is failed, err: " + err.Error())
	}
	return nil
}

// Jpeg 处理 jpg, jpeg
func Jpeg(dest io.Writer, src multipart.File, quality int, fn ...ToImgFn) error {
	toFn := nullFn
	if len(fn) > 0 {
		toFn = fn[0]
	}
	if quality < 0 {
		quality = jpeg.DefaultQuality
	}

	img, err := jpeg.Decode(src)
	if err != nil {
		return errors.New("jpeg.Decode is failed, err: " + err.Error())
	}
	if err := jpeg.Encode(dest, toFn(img), &jpeg.Options{
		Quality: quality,
	}); err != nil {
		internal.Error()
		return errors.New("jpeg.Encode is failed, err: " + err.Error())
	}
	return nil
}

// Gif
func Gif(dest io.Writer, src multipart.File, opt *gif.Options, fn ...ToImgFn) error {
	toFn := nullFn
	if len(fn) > 0 {
		toFn = fn[0]
	}

	img, err := gif.Decode(src)
	if err != nil {
		return errors.New("gif.Decode is failed, err: " + err.Error())
	}
	if err := gif.Encode(dest, toFn(img), opt); err != nil {
		return errors.New("jpeg.Encode is failed, err: " + err.Error())
	}
	return nil
}

// Bmp
func Bmp(dest io.Writer, src multipart.File, fn ...ToImgFn) error {
	toFn := nullFn
	if len(fn) > 0 {
		toFn = fn[0]
	}

	img, err := bmp.Decode(src)
	if err != nil {
		return errors.New("bmp.Decode is failed, err: " + err.Error())
	}
	if err := bmp.Encode(dest, toFn(img)); err != nil {
		return errors.New("png.Encode is failed, err:" + err.Error())
	}
	return nil
}

// Webp
func Webp(dest io.Writer, src multipart.File, fn ...ToImgFn) error {
	toFn := nullFn
	if len(fn) > 0 {
		toFn = fn[0]
	}

	img, err := webp.Decode(src)
	if err != nil {
		return errors.New("webp.Decode is failed, err: " + err.Error())
	}
	if err := png.Encode(dest, toFn(img)); err != nil {
		return errors.New("png.Encode is failed, err: " + err.Error())
	}
	return nil
}

// Rotate90 旋转90度
func Rotate90(m image.Image) image.Image {
	rotate90 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dy(), m.Bounds().Dx()))
	// 矩阵旋转
	for x := m.Bounds().Min.Y; x < m.Bounds().Max.Y; x++ {
		for y := m.Bounds().Max.X - 1; y >= m.Bounds().Min.X; y-- {
			//  设置像素点
			rotate90.Set(m.Bounds().Max.Y-x, y, m.At(y, x))
		}
	}
	return rotate90
}

// Rotate180 旋转180度
func Rotate180(m image.Image) image.Image {
	rotate180 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dx(), m.Bounds().Dy()))
	// 矩阵旋转
	for x := m.Bounds().Min.X; x < m.Bounds().Max.X; x++ {
		for y := m.Bounds().Min.Y; y < m.Bounds().Max.Y; y++ {
			//  设置像素点
			rotate180.Set(m.Bounds().Max.X-x, m.Bounds().Max.Y-y, m.At(x, y))
		}
	}
	return rotate180
}

// Rotate270 旋转270度
func Rotate270(m image.Image) image.Image {
	rotate270 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dy(), m.Bounds().Dx()))
	// 矩阵旋转
	for x := m.Bounds().Min.Y; x < m.Bounds().Max.Y; x++ {
		for y := m.Bounds().Max.X - 1; y >= m.Bounds().Min.X; y-- {
			// 设置像素点
			rotate270.Set(x, m.Bounds().Max.X-y, m.At(y, x))
		}
	}
	return rotate270
}
